package com.fortune.service.acl;

import com.fortune.dao.MAclMapper;
import com.fortune.dao.MAclModuleMapper;
import com.fortune.dto.acl.MAclDto;
import com.fortune.dto.acl.MAclModuleLevelDto;
import com.fortune.entity.MAcl;
import com.fortune.entity.MAclModule;
import com.fortune.util.LevelUtil;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class MTreeService {


    @Resource
    private MAclModuleMapper sysAclModuleMapper;
    @Resource
    private MCoreService sysCoreService;
    @Resource
    private MAclMapper sysAclMapper;

    public List<MAclModuleLevelDto> userAclTree(int userId) {
        List<MAcl> userAclList = sysCoreService.getUserAclList(userId);
        List<MAclDto> aclDtoList = Lists.newArrayList();
        for (MAcl acl : userAclList) {
            MAclDto dto = MAclDto.adapt(acl);
            dto.setHasAcl(true);
            dto.setChecked(true);
            aclDtoList.add(dto);
        }
        return aclListToTree(aclDtoList);
    }

    public List<MAclModuleLevelDto> roleTree(String roleId) {
        // 1、当前用户已分配的权限点
        List<MAcl> userAclList = sysCoreService.getCurrentUserAclList();
        // 2、当前角色分配的权限点
        List<MAcl> roleAclList = sysCoreService.getRoleAclList(roleId);
        // 3、当前系统所有权限点
        List<MAclDto> aclDtoList = Lists.newArrayList();

        Set<Integer> userAclIdSet = userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());
        Set<Integer> roleAclIdSet = roleAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        List<MAcl> allAclList = sysAclMapper.getAll();
        for (MAcl acl : allAclList) {
            MAclDto dto = MAclDto.adapt(acl);
            if (userAclIdSet.contains(acl.getId())) {
                dto.setHasAcl(true);
            }
            if (roleAclIdSet.contains(acl.getId())) {
                dto.setChecked(true);
            }
            aclDtoList.add(dto);
        }
        return aclListToTree(aclDtoList);
    }

    public List<MAclModuleLevelDto> aclListToTree(List<MAclDto> aclDtoList) {
        if (CollectionUtils.isEmpty(aclDtoList)) {
            return Lists.newArrayList();
        }
        List<MAclModuleLevelDto> aclModuleLevelList = aclModuleTree();

        Multimap<Integer, MAclDto> moduleIdAclMap = ArrayListMultimap.create();
        for(MAclDto acl : aclDtoList) {
            if (acl.getStatus() == 1) {
                moduleIdAclMap.put(acl.getAclModuleId(), acl);
            }
        }
        bindAclsWithOrder(aclModuleLevelList, moduleIdAclMap);
        return aclModuleLevelList;
    }

    public void bindAclsWithOrder(List<MAclModuleLevelDto> aclModuleLevelList, Multimap<Integer, MAclDto> moduleIdAclMap) {
        if (CollectionUtils.isEmpty(aclModuleLevelList)) {
            return;
        }
        for (MAclModuleLevelDto dto : aclModuleLevelList) {
            List<MAclDto> aclDtoList = (List<MAclDto>)moduleIdAclMap.get(dto.getId());
            if (CollectionUtils.isNotEmpty(aclDtoList)) {
                Collections.sort(aclDtoList, aclSeqComparator);
                dto.setAclList(aclDtoList);
            }
            bindAclsWithOrder(dto.getAclModuleList(), moduleIdAclMap);
        }
    }

    public List<MAclModuleLevelDto> aclModuleTree() {
        List<MAclModule> aclModuleList = sysAclModuleMapper.getAllAclModule();
        List<MAclModuleLevelDto> dtoList = Lists.newArrayList();
        for (MAclModule aclModule : aclModuleList) {
            dtoList.add(MAclModuleLevelDto.adapt(aclModule));
        }
        return aclModuleListToTree(dtoList);
    }

    public List<MAclModuleLevelDto> aclModuleListToTree(List<MAclModuleLevelDto> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return Lists.newArrayList();
        }
        // level -> [aclmodule1, aclmodule2, ...] Map<String, List<Object>>
        Multimap<String, MAclModuleLevelDto> levelAclModuleMap = ArrayListMultimap.create();
        List<MAclModuleLevelDto> rootList = Lists.newArrayList();

        for (MAclModuleLevelDto dto : dtoList) {
            levelAclModuleMap.put(dto.getLevel(), dto);
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }
        Collections.sort(rootList, aclModuleSeqComparator);
        transformAclModuleTree(rootList, LevelUtil.ROOT, levelAclModuleMap);
        return rootList;
    }

    public void transformAclModuleTree(List<MAclModuleLevelDto> dtoList, String level, Multimap<String, MAclModuleLevelDto> levelAclModuleMap) {
        for (int i = 0; i < dtoList.size(); i++) {
            MAclModuleLevelDto dto = dtoList.get(i);
            String nextLevel = LevelUtil.calculateLevel(level, dto.getId());
            List<MAclModuleLevelDto> tempList = (List<MAclModuleLevelDto>) levelAclModuleMap.get(nextLevel);
            if (CollectionUtils.isNotEmpty(tempList)) {
                Collections.sort(tempList, aclModuleSeqComparator);
                dto.setAclModuleList(tempList);
                transformAclModuleTree(tempList, nextLevel, levelAclModuleMap);
            }
        }
    }

    public Comparator<MAclModuleLevelDto> aclModuleSeqComparator = new Comparator<MAclModuleLevelDto>() {
        public int compare(MAclModuleLevelDto o1, MAclModuleLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    public Comparator<MAclDto> aclSeqComparator = new Comparator<MAclDto>() {
        public int compare(MAclDto o1, MAclDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };
}
